package com.tgy.MyFlowable.workflow.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.ctsi.core.common.entity.LoginUser;
import com.ctsi.core.common.exception.MarsException;
import com.ctsi.core.common.util.$;
import com.ctsi.core.common.util.SecurityUtil;
import com.ctsi.workflow.enums.FlwHandleTaskExceptionEnum;
import com.ctsi.workflow.service.IFlwCommonService;
import com.ctsi.workflow.util.BpmCommentUtil;
import lombok.RequiredArgsConstructor;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * 任务通用业务接口实现类
 *
 * @version 1.0
 * @author: wang xiao xiang
 * @date: 2021/8/19 16:59
 */
@Service
@RequiredArgsConstructor
public class FlwCommonServiceImpl implements IFlwCommonService {

    private static final String ASSIGNEE = "assignee";

    private static final String CANDIDATE = "candidate";

    private final TaskService taskService;

    private final HistoryService historyService;

    @Autowired
    private HttpServletRequest request;

    @Override
    public Task queryTask(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if ($.isNull(task)) {
            throw new MarsException(FlwHandleTaskExceptionEnum.TASK_NOT_EXIST);
        }
        return task;
    }

    @Override
    public void complete(String taskId) {
        taskService.complete(taskId);
    }

    @Override
    public void complete(String taskId, Map<String, Object> vars) {
        taskService.complete(taskId, vars);
    }

    @Override
    public void complete(List<String> taskIdList) {
        if ($.isNotEmpty(taskIdList)) {
            taskIdList.forEach(this::complete);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addComment(String taskId, String comment) {
        Task task = queryTask(taskId);
        String processInstanceId = task.getProcessInstanceId();
        Comment resultComment = taskService.addComment(taskId, processInstanceId, comment);
        //resultComment.setUserId(Convert.toStr(MarsContextHolder.getUserId()));
        resultComment.setUserId(Convert.toStr(SecurityUtil.getUsername(request).getId()));
        //记录审批操作
        taskService.saveComment(resultComment);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addCommentAndCompleteTask(String taskId, String assignee, String comment) {
        Task task = queryTask(taskId);
        DelegationState delegationState = task.getDelegationState();
        //委托给我，我还没解决的，需要先解决
        if ($.isNotEmpty(delegationState) && DelegationState.PENDING.equals(delegationState)) {
            String name = SecurityUtil.getUsername(request).getAccount();
            String resolveComment = BpmCommentUtil.genResolveComment(name);
            //添加解决意见
            addComment(taskId, resolveComment);
            //解决任务
            taskService.resolveTask(taskId);
            return;
        }

        if ($.isEmpty(assignee)) {
            //待办人为空，可能是组任务，需要先签收任务
            //Long loginUserId = MarsContextHolder.getUserId();
            LoginUser loginUser = SecurityUtil.getUsername(request);
            Long loginUserId = loginUser.getId();
            String name = loginUser.getAccount();
            //String name = SecurityUtil.getUsername(request).getAccount();
            String claimComment = BpmCommentUtil.genClaimComment(name);
            try {
                //添加签收意见
                addComment(taskId, claimComment);
                //签收
                taskService.claim(taskId, Convert.toStr(loginUserId));
            } catch (Exception e) {
                //在签收的瞬间可能被别人签收且完成，需要此时判断
                HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
                //获取到谁办理的
                String hisDoneAssignee = historicTaskInstance.getAssignee();
                if ($.isNotEmpty(hisDoneAssignee)) {
                    //办理人不为空，表示被人办理了，则抛异常签收失败
                    throw new MarsException(FlwHandleTaskExceptionEnum.TASK_HAS_BEEN_HANDLE);
                } else {
                    //否则的话，可能出现服务器内部异常
                    e.printStackTrace();
                    throw new MarsException(e.getMessage());
                }
            }
        }
        //保存意见
        addComment(taskId, comment);
        //完成任务
        complete(taskId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void smartCompleteNext(String processInstanceId) {
        //如果流程选项设置了相同处理人，且下个任务为一条任务，且指定的办理人与当前办理人相同，则自动完成
        List<Task> nextTaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if ($.isNotEmpty(nextTaskList)) {
            //任务只有一个才自动完成
            if (nextTaskList.size() == 1) {
                Task nextTask = nextTaskList.get(0);
                //下一任务的id
                String nextTaskId = nextTask.getId();
                //下一任务的处理人
                String nextTaskAssignee = nextTask.getAssignee();
                //生成自动完成的意见
                String comment = BpmCommentUtil.genSmartCompleteComment();
                //当前登录用户
                //String sysLoginUserId = $.toStr(MarsContextHolder.getUserId());
                String sysLoginUserId = $.toStr(SecurityUtil.getUsername(request).getId());
                //任务有指定审批人才去校验
                if ($.isNotEmpty(nextTaskAssignee)) {
                    //判断下一审批人是否跟当前登录人相同
                    if (nextTaskAssignee.equals(sysLoginUserId)) {
                        //完成任务并设置意见
                        addCommentAndCompleteTask(nextTaskId, nextTaskAssignee, comment);
                        //递归，继续获取下一任务判断是否自动完成
                        smartCompleteNext(processInstanceId);
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setNextAssignee(String processInstanceId, String nextAssignee) {
        List<Task> nextTaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if ($.isNotEmpty(nextTaskList)) {
            //任务只有一个才设置下一步审批人
            if (nextTaskList.size() == 1) {
                Task nextTask = nextTaskList.get(0);
                String nextTaskId = nextTask.getId();
                //先清空其待办人，候选人与候选组信息
                deleteTaskAssignees(nextTaskId);
                //再设置其待办人
                taskService.setAssignee(nextTaskId, nextAssignee);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setNextDueDate(String processInstanceId, String nextDueDate) {
        List<Task> nextTaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if ($.isNotEmpty(nextTaskList)) {
            //任务只有一个才设置下一步任务期限
            if (nextTaskList.size() == 1) {
                Task nextTask = nextTaskList.get(0);
                String nextTaskId = nextTask.getId();
                taskService.setDueDate(nextTaskId, DateUtil.parseDateTime(nextDueDate));
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setNextPriority(String processInstanceId, Integer nextPriority) {
        List<Task> nextTaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if ($.isNotEmpty(nextTaskList)) {
            //任务只有一个才设置下一步任务优先级
            if (nextTaskList.size() == 1) {
                Task nextTask = nextTaskList.get(0);
                String nextTaskId = nextTask.getId();
                taskService.setPriority(nextTaskId, nextPriority);
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTaskAssignees(String taskId) {
        taskService.getIdentityLinksForTask(taskId).forEach(identityLink -> {
            //获取人员类型
            String type = identityLink.getType();
            //删除其待办人
            if (ASSIGNEE.equals(type)) {
                String userId = identityLink.getUserId();
                if ($.isNotEmpty(userId)) {
                    taskService.deleteUserIdentityLink(taskId, null, type);
                }
            }
            //删除其候选人与候选组
            if (CANDIDATE.equals(type)) {
                String groupId = identityLink.getGroupId();
                if ($.isNotEmpty(groupId)) {
                    taskService.deleteCandidateGroup(taskId, groupId);
                }
                String userId = identityLink.getUserId();
                if ($.isNotEmpty(userId)) {
                    taskService.deleteCandidateUser(taskId, userId);
                }
            }
        });
    }
}
